/**
 * 
 */
package com.jbat.gwt.tiledmapcreator.client.custom;

import com.jbat.gwt.tiledmapcreator.client.common.color.Color;

import com.google.gwt.canvas.client.Canvas;
import com.google.gwt.canvas.dom.client.Context2d;
import com.google.gwt.dom.client.ImageElement;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.DragEndHandler;
import com.google.gwt.event.dom.client.DragEnterHandler;
import com.google.gwt.event.dom.client.DragHandler;
import com.google.gwt.event.dom.client.DragLeaveHandler;
import com.google.gwt.event.dom.client.DragOverHandler;
import com.google.gwt.event.dom.client.DragStartHandler;
import com.google.gwt.event.dom.client.DropHandler;
import com.google.gwt.event.dom.client.HasAllDragAndDropHandlers;
import com.google.gwt.event.dom.client.HasClickHandlers;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.touch.client.Point;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.HTMLPanel;
import com.google.gwt.user.client.ui.Image;

/**
 * TileMap wraps a canvas object in a panel so it can be generated via UiBinder.
 * 
 * <p>
 * This class does most of the work associated with EditMapView.
 */
public class TileMap extends Composite implements HasAllDragAndDropHandlers, HasClickHandlers {

  private HTMLPanel panel;
  private Canvas canvas;
  private Context2d context;

  public TileMap() {
    panel = new HTMLPanel("<div id='image'/><div id='canvas'/>");

    canvas = Canvas.createIfSupported();

    context = canvas.getContext2d();

    initWidget(panel);

    panel.add(canvas, "canvas");
  }

  /**
   * Adds an image to the panel.
   * 
   * <p>
   * In order to draw an image on the canvas, one has to be loaded. Given that the application is
   * allowing the loading of images from a public directory on the server, this application cannot
   * make use of a preloaded image resource. This is a major hole in the functionality and a result
   * of improper planning. This method should be removed as soon as the image resolution is done
   * properly, by use of an image resource.<br>
   * <br>
   * See Issue 1 at {@link https://code.google.com/p/tiledmapcreator/issues/detail?id=1} for more
   * details.
   * 
   * @param img the image to add to the panel
   */
  @Deprecated
  public void add(Image img) {
    img.setVisible(false);
    panel.add(img, "image");
  }

  @Override
  public HandlerRegistration addClickHandler(ClickHandler handler) {
    return canvas.addClickHandler(handler);
  }

  @Override
  public HandlerRegistration addDragEndHandler(DragEndHandler handler) {
    return canvas.addDragEndHandler(handler);
  }

  @Override
  public HandlerRegistration addDragEnterHandler(DragEnterHandler handler) {
    return canvas.addDragEnterHandler(handler);
  }

  @Override
  public HandlerRegistration addDragHandler(DragHandler handler) {
    return canvas.addDragHandler(handler);
  }

  @Override
  public HandlerRegistration addDragLeaveHandler(DragLeaveHandler handler) {
    return canvas.addDragLeaveHandler(handler);
  }

  @Override
  public HandlerRegistration addDragOverHandler(DragOverHandler handler) {
    return canvas.addDragOverHandler(handler);
  }

  @Override
  public HandlerRegistration addDragStartHandler(DragStartHandler handler) {
    return canvas.addDragStartHandler(handler);
  }

  @Override
  public HandlerRegistration addDropHandler(DropHandler handler) {
    return canvas.addDropHandler(handler);
  }

  /**
   * Draws an image in the given tile location.
   * 
   * @param imageElement the image to draw
   * @param xPos the target x position (will be the top left)
   * @param yPos the target y position (will be the top left)
   * @param width the width of the image
   * @param height the height of the image
   */
  public void drawImageAt(ImageElement imageElement, int xPos, int yPos, int width, int height) {
    context.drawImage(imageElement, xPos, yPos, width, height);
  }

  /**
   * Draws a line of the given color from the given start point to the given end point.
   * 
   * @param color the color to use (in any number of formats, but expecting rgb(#,#,#) where # can
   *          be between 0 and 255
   * @param start the Point from which to start drawing
   * @param end the Point at which to end
   */
  public void drawLine(Color color, Point start, Point end) {
    context.beginPath();

    // set stroke style for the context
    context.setStrokeStyle(color.getRgbString());
    context.setLineWidth(2.0); // line width is two because line will spill into the neighboring
                               // pixels anyway

    context.moveTo(start.getX(), start.getY());
    context.lineTo(end.getX(), end.getY());
    context.stroke();
  }

  /**
   * Draws a rectangle with the given color starting at the given point, with width and height equal
   * to the inputs.
   * 
   * @param color the color to use 
   * @param upperLeft the upper left point to begin drawing from
   * @param width the width of the rectangle
   * @param height the height of the rectangle
   */
  public void drawRect(Color color, Point upperLeft, int width, int height) {
    context.beginPath();

    // set the style
    context.setStrokeStyle(color.getRgbString());
    context.setLineWidth(2.0);

    context.rect(upperLeft.getX(), upperLeft.getY(), width, height);
    context.stroke();
  }

  /**
   * Set the coordinate space height and width of the canvas.
   * 
   * @param xUnits width
   * @param yUnits height
   */
  public void setMapUnits(int xUnits, int yUnits) {
    canvas.setCoordinateSpaceWidth(xUnits);
    canvas.setCoordinateSpaceHeight(yUnits);
  }
}
